import { Injectable, Logger } from '@nestjs/common';
import axios from 'axios';
import { ICalculateDailyCalories, IFindFood } from './pfc.dto';
import { INutritionixRes } from './interfaces/nutritionix.interface';
import { IFood } from './interfaces/food.interface';
import { InjectRepository } from '@nestjs/typeorm';
import { User } from 'libs/database/entities/users.entity';
import { Between, Repository } from 'typeorm';
import { UserStats } from 'libs/database/entities/users-stats.entity';
import { Food } from 'libs/database/entities/food.entity';
import { EGender } from 'libs/enums/gender.enum';
import { EActivityLevel } from 'libs/enums/activityLevel.enum';
import { EGoal } from 'libs/enums/goal.enum';
import { config } from 'config';
import * as translate from 'translatte';

@Injectable()
export class PFCService {
    private readonly logger: Logger = new Logger(PFCService.name);

    constructor(
        @InjectRepository(User) private userRepository: Repository<User>,
        @InjectRepository(UserStats) private userStatsRepository: Repository<UserStats>,
        @InjectRepository(Food) private foodRepository: Repository<Food>
    ) {}

    private getActivityMultiplier(activityLevel: EActivityLevel) {
        const levels = {
            sedentary: 1.2,
            lightlyActive: 1.375,
            moderatelyActive: 1.55,
            veryActive: 1.725,
        };

        return levels[activityLevel];
    }

    private getGoalMultiplier(goal: EGoal) {
        const goals = {
            loseWeight: 1,
            maintainWeight: 0.8,
            gainWeight: 1.2,
        };

        return goals[goal];
    }

    async calculateDailyCalories(userTelegramId: string, data: ICalculateDailyCalories) {
        // Базовая метаболическая скорость в зависимости от пола
        const bmr =
            data.gender === EGender.male
                ? 88.362 + 13.397 * data.weightKg + 4.799 * data.heightCm - 5.677 * data.age
                : 4447.593 + 9.247 * data.weightKg + 3.098 * data.heightCm - 4.33 * data.age;

        // множитель активности в зависимости от уровня физ активности
        const activityMultiplier = this.getActivityMultiplier(data.activityLevel);

        // множитель целей
        const goalMultiplier = this.getGoalMultiplier(data.goal);

        const dailyCalories = bmr * activityMultiplier * goalMultiplier;

        return dailyCalories;
    }

    private async addFood(userTelegramId: string, data: IFood): Promise<IFood | null> {
        try {
            this.logger.debug(`[pfc.addFood] data: ${JSON.stringify(data)}`);

            const date = new Date();
            const startOfDay = new Date(date);
            startOfDay.setHours(3, 0, 0, 0);
            const endOfDay = new Date(date);
            endOfDay.setHours(26, 59, 59, 999);

            const user = await this.userRepository.findOne({ where: { telegramId: userTelegramId } });
            if (!user) {
                this.logger.warn(`User (${userTelegramId}) not found`);
                return null;
            }

            await this.foodRepository.save({
                userTelegramId: userTelegramId,
                nameFood: data.name,
                calories: data.calories,
                carbohydrate: data.carbohydrate,
                totalFat: data.totalFat,
                protein: data.protein,
                urlImage: data.urlImage,
            });

            const userStat = await this.userStatsRepository.findOne({
                where: { userTelegramId: userTelegramId, date: Between(startOfDay, endOfDay) },
            });
            const userStatModel = new UserStats({
                userTelegramId: userTelegramId,
                calories: data.calories,
                carbohydrate: data.carbohydrate,
                totalFat: data.totalFat,
                protein: data.protein,
                date: date,
            });

            if (userStat) {
                userStatModel.id = userStat.id;
                userStatModel.calories = Number(
                    (userStatModel.calories + Number(userStat.calories)).toFixed(3).slice(0, -1)
                );
                userStatModel.carbohydrate = Number(
                    (userStatModel.carbohydrate + Number(userStat.carbohydrate)).toFixed(3).slice(0, -1)
                );
                userStatModel.totalFat = Number(
                    (userStatModel.totalFat + Number(userStat.totalFat)).toFixed(3).slice(0, -1)
                );
                userStatModel.protein = Number(
                    (userStatModel.protein + Number(userStat.protein)).toFixed(3).slice(0, -1)
                );
                userStatModel.date = userStat.date;
            }

            await this.userStatsRepository.save(userStatModel);
            return data;
        } catch (error) {
            this.logger.error(`[pfc.addFood] error`, error);
        }
    }

    private async translate(to: string, text: string) {
        try {
            this.logger.debug(`[bot.translate] to: ${to}; text: ${text}`);
            const newText = await translate(text, { to: to });
            return newText;
        } catch (error) {
            this.logger.error(`[bot.translate] error`, error);
        }
    }

    async addNewFood(userTelegramid: string, data: IFindFood) {
        try {
            this.logger.debug(`[pfc.addNewFood] user: ${userTelegramid}; data: ${JSON.stringify(data)}`);

            const NATURAL_URL = config.natural.url;
            const headers = {
                'Content-Type': 'application/json',
                'x-app-id': config.natural.appId,
                'x-app-key': config.natural.appKey,
            };
            const foodOnEnglish = await this.translate('en', data.food);
            console.log(foodOnEnglish.text);

            let body = {
                query: foodOnEnglish.text,
                timezone: 'US/Eastern',
            };
            // let body = {
            //     query: 'Chicken with buckwheat',
            //     timezone: 'US/Eastern',
            // };

            const Body = JSON.stringify(body);

            const foods = await axios.post(NATURAL_URL, Body, { headers: headers });
            const info: IFood[] = [];
            for (let food of foods.data.foods) {
                const infoFood: INutritionixRes = food;

                const result = await this.addFood(userTelegramid, {
                    name: infoFood.food_name,
                    calories: infoFood.nf_calories,
                    carbohydrate: infoFood.nf_total_carbohydrate,
                    protein: infoFood.nf_protein,
                    totalFat: infoFood.nf_total_fat,
                    urlImage: infoFood.photo.thumb,
                });
                if (result) info.push(result);
            }
            const res: IFood = { name: 'result', urlImage: '', calories: 0, carbohydrate: 0, protein: 0, totalFat: 0 };
            for (let resFood of info) {
                resFood.name = (await this.translate('ru', resFood.name)).text;
                res.calories += resFood.calories;
                res.carbohydrate += resFood.carbohydrate;
                res.protein += resFood.protein;
                res.totalFat += resFood.totalFat;
            }

            info.push(res);

            return info;
        } catch (error) {
            this.logger.error(`[pfc.getNotesByUser] error`, error);
        }
    }

    async getAllFoodTodayByUser(userTelegramId: string) {
        try {
            this.logger.debug(`[pfc.getAllFoodTodayByUser] user: ${userTelegramId}`);

            const date = new Date();
            const startOfDay = new Date(date);
            startOfDay.setHours(3, 0, 0, 0);
            const endOfDay = new Date(date);
            endOfDay.setHours(26, 59, 59, 999);

            const allFoods = await this.foodRepository.find({
                where: { userTelegramId: userTelegramId, createdAt: Between(startOfDay, endOfDay) },
            });

            for (let food of allFoods) {
                food.nameFood = food.nameFood = (await this.translate('ru', food.nameFood)).text;
            }

            return allFoods;
        } catch (error) {
            this.logger.error(`[pfc.getAllFoodTodayByUser] error`, error);
        }
    }

    async getAllCaloriesTodayByUser(userTelegramId: string) {
        try {
            this.logger.debug(`[pfc.getAllCaloriesTodayByUser] user: ${userTelegramId}`);

            const date = new Date();
            const startOfDay = new Date(date);
            startOfDay.setHours(3, 0, 0, 0);
            const endOfDay = new Date(date);
            endOfDay.setHours(26, 59, 59, 999);

            const todayStats = await this.userStatsRepository.findOne({
                where: { userTelegramId: userTelegramId, date: Between(startOfDay, endOfDay) },
            });

            return todayStats;
        } catch (error) {
            this.logger.error(`[pfc.getAllFoodTodayByUser] error`, error);
        }
    }
}
